home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 04 - 1988 / 04.11 Nov 88 / Window Menu Source / wMenu.p next >
Encoding:
Text File  |  1988-02-12  |  16.4 KB  |  493 lines  |  [TEXT/PJMM]

  1. { wMenu Manager }
  2. { by Jim Matthews }
  3.  
  4. UNIT wMenu;
  5.  
  6. INTERFACE
  7.  
  8.     USES
  9.         ROM85;                    { uses HGetState and HSetState }
  10.  
  11.     CONST
  12.         mBarHeight = 20;
  13.         betweenTitles = 15;        { # of pixels between adjacent menu titles }
  14.         invertOverlap = 10;        { # of pixels to invert on each side of a menu title }
  15.         noneHilited = -1;            { value to store in wMenuBar.hilited if nothing hilited }
  16.         menuTitleBit = 31;        { mac-style bit offset for menu title bit in enableFlags }
  17.  
  18.     TYPE
  19.         wMenuRec = RECORD
  20.                 mh : MenuHandle;
  21.                 titleRect : Rect;
  22.             END;
  23.         wMenuBar = RECORD
  24.                 numMenus : integer;
  25.                 hilited : integer;
  26.                 gp : GrafPtr;
  27.                 wMenus : ARRAY[0..0] OF wMenuRec;
  28.             END;
  29.         wMenuBarPtr = ^wMenuBar;
  30.         wMenuBarHandle = ^wMenuBarPtr;
  31.  
  32.     FUNCTION wInitMenus (gp : GrafPtr) : wMenuBarHandle;
  33.     PROCEDURE wInsertMenu (theMenuBar : wMenuBarHandle;
  34.                                     theMenu : MenuHandle;
  35.                                     beforeID : integer);
  36.     PROCEDURE wDrawMenuBar (theMenuBar : wMenuBarHandle);
  37.     PROCEDURE wDeleteMenu (theMenuBar : wMenuBarHandle;
  38.                                     menuID : integer);
  39.     PROCEDURE wClearMenuBar (theMenuBar : wMenuBarHandle);
  40.  
  41.     FUNCTION wMenuSelect (theMenuBar : wMenuBarHandle;
  42.                                     startPt : Point) : longint;
  43.     FUNCTION wMenuKey (theMenuBar : wMenuBarHandle;
  44.                                     ch : char) : longint;
  45.     PROCEDURE wHiliteMenu (theMenuBar : wMenuBarHandle;
  46.                                     menuID : integer);
  47.  
  48. IMPLEMENTATION
  49.  
  50. {wInitMenus -- create a wMenuBar and associate it with a grafport}
  51.     FUNCTION wInitMenus;         { (gp : GrafPtr) : wMenuBarHandle; }
  52.         TYPE
  53.             intptr = ^Integer;
  54.         VAR
  55.             mbar : wMenuBarHandle;
  56.             TopMenuItemP : intptr;
  57.     BEGIN
  58.     { Set low-mem global to fix menu display bug }
  59.         TopMenuItemP := intptr($A0A);
  60.         TopMenuItemP^ := mBarHeight;
  61.  
  62.         mbar := wMenuBarHandle(NewHandle(sizeof(wMenuBar)));
  63.         mbar^^.numMenus := 0;
  64.         mbar^^.hilited := noneHilited;
  65.         mbar^^.gp := gp;
  66.         wInitMenus := mbar;
  67.     END; { wInitMenus }
  68.  
  69. {wInsertMenu -- insert a menu into a defined wMenuBar, analogous to InsertMenu }
  70.     PROCEDURE wInsertMenu;     { (theMenuBar : wMenuBarHandle; }
  71.                                     { theMenu : MenuHandle; }
  72.                                     { beforeID : integer); }
  73.         VAR
  74.             newSize : Size;
  75.             r : Rect;
  76.             i, j : integer;
  77.             titleWidth, oldSize, oldFont : integer;
  78.     BEGIN
  79.         newSize := sizeof(wMenuBar) + theMenuBar^^.numMenus * sizeof(wMenuRec);
  80.         IF newSize > GetHandleSize(handle(theMenuBar)) THEN
  81.             SetHandleSize(handle(theMenuBar), newSize);
  82.         IF MemError = noErr THEN
  83.             BEGIN
  84.                 oldSize := thePort^.txSize;
  85.                 oldFont := thePort^.txFont;
  86.                 TextSize(12);
  87.                 TextFont(systemFont);
  88.                 titleWidth := StringWidth(theMenu^^.menuData);
  89.                 TextSize(oldSize);
  90.                 TextFont(oldFont);
  91.                 i := 0;
  92.                 IF beforeID > 0 THEN        { Insert the menu before a particular one? }
  93.                     BEGIN
  94.                         i := 0;
  95.                         WHILE (theMenuBar^^.wMenus[i].mh^^.menuID <> beforeID) AND (i < theMenuBar^^.numMenus) DO
  96.                             i := i + 1;
  97.                         IF i <> theMenuBar^^.numMenus THEN
  98.                             BEGIN
  99.                                 FOR j := theMenuBar^^.numMenus DOWNTO i + 1 DO
  100.                                     BEGIN
  101.                                         theMenuBar^^.wMenus[j].mh := theMenuBar^^.wMenus[j - 1].mh;
  102.                                         theMenuBar^^.wMenus[j].titleRect := theMenuBar^^.wMenus[j - 1].titleRect;
  103.                                         OffsetRect(theMenuBar^^.wMenus[j].titleRect, titleWidth + betweenTitles, 0);
  104.                                     END; { for loop -- copying menus back }
  105.                             END; { if there's a menu id = beforeID }
  106.                     END { if beforeID <> 0 }
  107.                 ELSE                            { if beforeID <= 0, put it after the rest }
  108.                     i := theMenuBar^^.numMenus;
  109.                 WITH theMenuBar^^.wMenus[i] DO
  110.                     BEGIN
  111.                         titleRect.top := 1;
  112.                         titleRect.bottom := mBarHeight - 1;
  113.                         IF i = 0 THEN
  114.                             titleRect.left := betweenTItles - invertOverlap
  115.                         ELSE
  116.                             titleRect.left := theMenuBar^^.wMenus[i - 1].titleRect.right + betweenTitles - 2 * invertOverlap;
  117.                         titleRect.right := titleRect.left + titleWidth + 2 * invertOverlap;
  118.                         mh := theMenu;
  119.                     END; { with theMenuBar^^.wMenus[i] }
  120.                 theMenuBar^^.numMenus := theMenuBar^^.numMenus + 1;
  121.             END; { no MemError }
  122.     END; { wInsertMenu }
  123.  
  124. { wDrawMenuBar -- draw the wMenuBar, with appropriate highlighting }
  125.     PROCEDURE wDrawMenuBar;            { (theMenuBar : wMenuBarHandle); }
  126.         VAR
  127.             i : integer;
  128.             r : Rect;
  129.             oldPort : GrafPtr;
  130.             oldSize, oldFont, oldMode : integer;
  131.             oldStyle : Style;
  132.             bmap, oldMap : BitMap;
  133.     BEGIN
  134.         GetPort(oldPort);
  135.         SetPort(theMenuBar^^.gp);
  136.         oldSize := thePort^.txSize;
  137.         oldFont := thePort^.txFont;
  138.         oldMode := thePort^.txMode;
  139.         oldStyle := thePort^.txFace;
  140.         TextSize(12);
  141.         TextFont(systemFont);
  142.         TextMode(srcOr);
  143.         TextFace([]);
  144.  
  145.         SetRect(r, 0, 0, 10000, mBarHeight);
  146.         EraseRect(r);
  147.         MoveTo(0, mBarHeight - 1);
  148.         Line(10000, 0);
  149.  
  150.         FOR i := 0 TO theMenuBar^^.numMenus - 1 DO
  151.             BEGIN
  152.                 MoveTo(theMenuBar^^.wMenus[i].titleRect.left + invertOverlap, mBarHeight - 5);
  153.                 DrawString(theMenuBar^^.wMenus[i].mh^^.menuData);
  154.  
  155.         { gray-out disabled menu titles }
  156.                 IF NOT BitTst(@theMenuBar^^.wMenus[i].mh^^.enableFlags, menuTitleBit) THEN
  157.                     BEGIN
  158.                         r := theMenuBar^^.wMenus[i].titleRect;
  159.                         r.left := r.left + invertOverlap;
  160.                         r.right := r.right - invertOverlap;
  161.                         bmap.bounds := r;
  162.                         OffsetRect(bmap.bounds, -r.left, -r.top);
  163.                         IF (bmap.bounds.right MOD 16) <> 0 THEN
  164.                             bmap.rowBytes := 2 * ((bmap.bounds.right DIV 16) + 1)
  165.                         ELSE
  166.                             bmap.rowBytes := 2 * (bmap.bounds.right DIV 16);
  167.                         bmap.baseAddr := NewPtr(bmap.rowBytes * mBarHeight);
  168.                         oldMap := thePort^.portBits;
  169.                         SetPortBits(bmap);
  170.                         FillRect(bmap.bounds, gray);
  171.                         SetPortBits(oldMap);
  172.                         HLock(handle(theMenuBar));
  173.                         CopyBits(bmap, thePort^.portBits, bmap.bounds, r, notSrcBic, NIL);
  174.                         HUnlock(handle(theMenuBar));
  175.                         DisposPtr(bmap.baseAddr);
  176.                     END; { if title disabled }
  177.             END; { for each menu }
  178.         IF theMenuBar^^.hilited <> noneHilited THEN
  179.             InvertRect(theMenuBar^^.wMenus[theMenuBar^^.hilited].titleRect);
  180.  
  181.         TextSize(oldSize);
  182.         TextFont(oldFont);
  183.         TextMode(oldMode);
  184.         TextFace(oldStyle);
  185.         SetPort(oldPort);
  186.     END; { wDrawMenuBar }
  187.  
  188. {wDeleteMenu -- delete a menu from a wMenuBar}
  189.     PROCEDURE wDeleteMenu;         { (theMenuBar : wMenuBarHandle; }
  190.                                         { menuID : integer); }
  191.         VAR
  192.             i, j, oldSize, oldFont : integer;
  193.             oldStyle : Style;
  194.             titleWidth : integer;
  195.     BEGIN
  196.         oldSize := thePort^.txSize;        { reset the font/size/style to compute menu title widths }
  197.         oldFont := thePort^.txFont;
  198.         oldStyle := thePort^.txFace;
  199.         TextSize(12);
  200.         TextFont(systemFont);
  201.         TextFace([]);
  202.  
  203.         i := 0;
  204.         WHILE (theMenuBar^^.wMenus[i].mh^^.menuID <> menuID) AND (i < theMenuBar^^.numMenus) DO
  205.             i := i + 1;
  206.         IF i <> theMenuBar^^.numMenus THEN
  207.             BEGIN
  208.                 titleWidth := StringWidth(theMenuBar^^.wMenus[i].mh^^.menuData);
  209.                 FOR j := i TO theMenuBar^^.numMenus - 1 DO
  210.                     BEGIN
  211.                         theMenuBar^^.wMenus[j].mh := theMenuBar^^.wMenus[j + 1].mh;
  212.                         theMenuBar^^.wMenus[j].titleRect := theMenuBar^^.wMenus[j + 1].titleRect;
  213.                         OffsetRect(theMenuBar^^.wMenus[j].titleRect, -(titleWidth + betweenTitles), 0);
  214.                     END; { for loop -- copying menus back }
  215.                 theMenuBar^^.numMenus := theMenuBar^^.numMenus - 1;
  216.             END; { if there's a menu id = menuID }
  217.  
  218.         TextSize(oldSize);
  219.         TextFont(oldFont);
  220.         TextFace(oldStyle);
  221.     END; { wDeleteMenu }
  222.  
  223. {wClearMenuBar -- delete all the menus in a menu bar}
  224.     PROCEDURE wClearMenuBar;        { (theMenuBar : wMenuBarHandle); }
  225.     BEGIN
  226.         theMenuBar^^.numMenus := 0;    { take the easy way out.... }
  227.     END; { wClearMenuBar }
  228.  
  229. {MenuDefProc -- inline call to the menu definition procedure}
  230. {        Pop the address of the proc off the stack and jsr to it}
  231.     PROCEDURE MenuDefProc (message : integer;
  232.                                     theMenu : MenuHandle;
  233.                                     VAR menuRect : Rect;
  234.                                     hitPt : Point;
  235.                                     VAR whichItem : integer;
  236.                                     theProc : ProcPtr);
  237.     INLINE
  238.         $205F, $4E90;    { pop.l A0 , jsr (A0) }
  239.  
  240. {MenuDefGlue -- dereference the menu handle to find the address of}
  241. {    the definition procedure and call it using MenuDefProc, above}
  242.     PROCEDURE MenuDefGlue (message : integer;
  243.                                     theMenu : MenuHandle;
  244.                                     VAR menuRect : Rect;
  245.                                     hitPt : Point;
  246.                                     VAR whichItem : integer);
  247.     BEGIN
  248.         MenuDefProc(message, theMenu, menuRect, hitPt, whichItem, theMenu^^.menuProc^);
  249.     END;
  250.  
  251. {wMenuSelect -- pull down the menus and let the user select an item}
  252.     FUNCTION wMenuSelect;             { (theMenuBar : wMenuBarHandle; }
  253.                                         { startPt : Point) : longint; }
  254.         CONST
  255.             flashDelay = 3;                { # of ticks between calls to invert selected item }
  256.             menuFrame = 2;            { width of menu frame }
  257.             MenuFlashAddr = $A24;    { address of lo-mem global: # of times to flash menu }
  258.         TYPE
  259.             intPtr = ^integer;
  260.         VAR
  261.             bmap : BitMap;
  262.             menuRect : Rect;
  263.             oldClip : RgnHandle;
  264.             nilPt : Point;
  265.             blink, whichItem : integer;
  266.             oldPort, wMgrPort : GrafPtr;
  267.             i : integer;
  268.             hstate, mprocState : SignedByte;
  269.             ticks : longint;
  270.             menuFlashP : intPtr;
  271.             oldSize, oldFont, oldMode : integer;
  272.             pnState : PenState;
  273.             strayed : boolean;
  274.             dummyEvt : EventRecord;
  275.     BEGIN
  276.         hState := HGetState(handle(theMenuBar));
  277.         HLock(handle(theMenuBar));
  278.         GetPort(oldPort);
  279.         SetPort(theMenuBar^^.gp);
  280.         oldSize := thePort^.txSize;
  281.         oldFont := thePort^.txFont;
  282.         oldMode := thePort^.txMode;
  283.         TextSize(12);
  284.         TextFont(systemFont);
  285.         TextMode(srcOr);
  286.         menuFlashP := intPtr(MenuFlashAddr);
  287.         whichItem := 0;
  288.         WHILE WaitMouseUp DO                    { loop while the mouse is down }
  289.             BEGIN
  290.         { find menu title that user is clicking on }
  291.                 i := theMenuBar^^.numMenus - 1;
  292.                 WHILE (i >= 0) AND NOT PtInRect(startPt, theMenuBar^^.wMenus[i].titleRect) DO
  293.                     i := i - 1;
  294.  
  295.         { if user is clicking on a menu title, have the menu "drop down" }
  296.                 IF i >= 0 THEN
  297.                     WITH theMenuBar^^.wMenus[i] DO        { note: theMenuBar is locked }
  298.                         BEGIN
  299.                             wHiliteMenu(theMenuBar, mh^^.menuID);        { hilite title }
  300.                             CalcMenuSize(mh);                { calculate menu size, it may have changed }
  301.                             SetRect(menuRect, titleRect.left + 1, mBarHeight, titleRect.left + mh^^.menuWidth + 1, mBarHeight + mh^^.menuHeight);
  302.                             InsetRect(menuRect, -menuFrame, -menuFrame);
  303.  
  304.             { if the menu overlaps the edges of the window, trim it }
  305.                             IF menuRect.bottom > thePort^.portRect.bottom THEN
  306.                                 menuRect.bottom := thePort^.portRect.bottom;
  307.                             IF menuRect.right > thePort^.portRect.right THEN
  308.                                 OffsetRect(menuRect, thePort^.portRect.right - menuRect.right - 2, 0);
  309.                             IF menuRect.left < 0 THEN
  310.                                 OffsetRect(menuRect, -menuRect.left, 0);
  311.                             bmap.rowBytes := ((menuRect.right - menuRect.left + 15) DIV 16) * 2;
  312.                             bmap.bounds := menuRect;
  313.                             bmap.baseAddr := NewPtr(bmap.rowBytes * (menuRect.bottom - menuRect.top));
  314.                             IF bmap.baseAddr <> NIL THEN        { proceed if there is memory }
  315.                                 BEGIN
  316.                                     CopyBits(thePort^.portBits, bmap, bmap.bounds, bmap.bounds, srcCopy, NIL);
  317.                                     oldClip := NewRgn;
  318.                                     GetClip(oldClip);
  319.                                     ClipRect(menuRect);
  320.  
  321.                 { draw the menu -- thanks to Mike Schuster, MacTutor 12/85 }
  322.                                     IF mh^^.menuHeight > 0 THEN
  323.                                         BEGIN
  324.                                             InsetRect(menuRect, menuFrame, menuFrame);
  325.                                             EraseRect(menuRect);
  326.                                             InsetRect(menuRect, -1, -1);
  327.                                             FrameRect(menuRect);
  328.                                             InsetRect(menuRect, 1, 1);
  329.  
  330.                                             GetPenState(pnState);
  331.                                             PenNormal;
  332.                                             MoveTo(menuRect.left + 1, menuRect.bottom + 1);
  333.                                             Line((menuRect.right - menuRect.left), 0);
  334.                                             Line(0, -(menuRect.bottom - menuRect.top));
  335.                                             SetPenState(pnState);
  336.                                         END; { if there're any menu items }
  337.  
  338.                                     LoadResource(mh^^.menuProc);
  339.                                     mprocState := HGetState(handle(mh^^.menuProc));
  340.                                     HLock(mh^^.menuProc);
  341.                                     whichItem := 0;
  342.                                     MenuDefGlue(mDrawMsg, mh, menuRect, startPt, whichItem);
  343.  
  344.                 { send the mChooseMsg while the user is still in this menu }
  345.                                     strayed := false;
  346.                                     WHILE WaitMouseUp AND NOT strayed DO
  347.                                         BEGIN
  348.                                             MenuDefGlue(mChooseMsg, mh, menuRect, startPt, whichItem);
  349.                                             GetMouse(startPt);
  350.                                             strayed := (startPt.v < mBarHeight - 1) AND (startPt.v > 0) AND (NOT PtInRect(startPt, titleRect));
  351.                                             IF i < theMenuBar^^.numMenus - 1 THEN
  352.                                                 strayed := strayed OR ((startPt.v < mBarHeight - 1) AND (startPt.v > 0) AND PtInRect(startPt, theMenuBar^^.wMenus[i + 1].titleRect));
  353.  
  354.                     { Enable FKeys (i.e. screen dump) and DA updating }
  355.                                             IF EventAvail(everyEvent, dummyEvt) THEN
  356.                                                 ;
  357.                                             SystemTask;
  358.                                         END; { while WaitMouseUp and not strayed }
  359.  
  360.                 { flash the menu if an item was selected }
  361.                                     IF (whichItem <> 0) AND NOT strayed THEN
  362.                                         FOR blink := 1 TO menuFlashP^ DO
  363.                                             BEGIN
  364.                                                 SetPt(nilPt, 0, 0);
  365.                                                 MenuDefGlue(mChooseMsg, mh, menuRect, nilPt, whichItem);
  366.                                                 Delay(flashDelay, ticks);
  367.                                                 MenuDefGlue(mChooseMsg, mh, menuRect, startPt, whichItem);
  368.                                                 Delay(flashDelay, ticks);
  369.                                             END; { whichItem <> 0 }
  370.                                     HSetState(mh^^.menuProc, mprocState);
  371.                                     SetClip(oldClip);
  372.                                     DisposeRgn(oldClip);
  373.                                     CopyBits(bmap, thePort^.portBits, bmap.bounds, bmap.bounds, srcCopy, NIL);
  374.                                     DisposPtr(bmap.baseAddr);
  375.                                 END; { memory for bitmap }
  376.                         END { i >= 0: found the hit menu title }
  377.                 ELSE
  378.                     BEGIN        { user isn't over a menu, so unhilite the last one hilited }
  379.                         IF theMenuBar^^.hilited <> noneHilited THEN
  380.                             wHiliteMenu(theMenuBar, 0);
  381.                         GetMouse(startPt);        { need a new startPt -- mouse may have moved }
  382.                     END;{ no menu currently selected }
  383.             END; { while WaitMouseUp -- looking for a hit menu title}
  384.  
  385.     { user let up on the mouse -- return the appropriate value }
  386.         IF whichItem = 0 THEN
  387.             wMenuSelect := 0
  388.         ELSE
  389.             wMenuSelect := BitShift(theMenuBar^^.wMenus[i].mh^^.menuID, 16) + whichItem;
  390.         TextSize(oldSize);
  391.         TextFont(oldFont);
  392.         TextMode(oldMode);
  393.         SetPort(oldPort);
  394.         HSetState(handle(theMenuBar), hState);
  395.     END; { wMenuSelect }
  396.  
  397. {wMenuKey -- return the menu id and item no. with ch as it's cmd-key equivalent }
  398. {    Caution: this assumes knowledge of the internal structure of  MenuInfo.menuData }
  399.     FUNCTION wMenuKey;                { (theMenuBar : wMenuBarHandle; }
  400.                                         { ch : char) : longint; }
  401.         CONST
  402.             flashDelay = 3;
  403.         TYPE
  404.             SignedBytePtr = ^SignedByte;
  405.             CharPtr = ^char;
  406.         VAR
  407.             hState : SignedByte;
  408.             bp, keyEquivP : SignedBytePtr;
  409.             i, j, whichMenu, whichItem : integer;
  410.             done, enabled : boolean;
  411.             ticks : longint;
  412.  
  413.     { compare alphabetic characters w/o case sensitivity }
  414.         FUNCTION equalChars (c1, c2 : char) : boolean;
  415.         BEGIN
  416.             IF c1 IN ['a'..'z'] THEN
  417.                 c1 := char(ord(c1) + ord('A') - ord('a'));
  418.             IF c2 IN ['a'..'z'] THEN
  419.                 c2 := char(ord(c2) + ord('A') - ord('a'));
  420.             equalChars := c1 = c2;
  421.         END;
  422.  
  423.     BEGIN
  424.         i := 0;
  425.         done := false;
  426.         WHILE (NOT done) AND (i < theMenuBar^^.numMenus) DO
  427.             BEGIN
  428.                 hState := HGetState(handle(theMenuBar^^.wMenus[i].mh));
  429.                 HLock(handle(theMenuBar^^.wMenus[i].mh));
  430.  
  431.         { run down a menu, looking for an item w/ ch as its key equivalent }
  432.                 j := 1;
  433.                 bp := SignedBytePtr(@theMenuBar^^.wMenus[i].mh^^.menuData);
  434.                 bp := SignedBytePtr(ord4(bp) + bp^ + 1);
  435.                 WHILE (NOT done) AND (bp^ <> 0) DO
  436.                     BEGIN
  437.                         keyEquivP := SignedBytePtr(ord4(bp) + bp^ + 2);
  438.                         IF equalChars(ch, char(keyEquivP^)) THEN
  439.                             BEGIN
  440.                                 whichMenu := theMenuBar^^.wMenus[i].mh^^.menuID;
  441.                                 whichItem := j;
  442.                                 done := true;
  443.                             END
  444.                         ELSE
  445.                             BEGIN
  446.                                 j := j + 1;
  447.                                 bp := SignedBytePtr(ord4(keyEquivP) + 3);
  448.                             END;
  449.                     END; { looking through this menu }
  450.  
  451.                 HSetState(handle(theMenuBar^^.wMenus[i].mh), hState);
  452.                 i := i + 1;
  453.             END; { while loop -- looking for key equiv }
  454.     {the item is enabled if both it and its menu title are}
  455.         enabled := BitTst(@theMenuBar^^.wMenus[i - 1].mh^^.enableFlags, menuTitleBit);
  456.         enabled := enabled AND (j < 32) AND (BitTst(@theMenuBar^^.wMenus[i - 1].mh^^.enableFlags, menuTitleBit - j));
  457.         IF done AND enabled THEN
  458.             BEGIN
  459.                 wHiliteMenu(theMenuBar, whichMenu);
  460.                 wMenuKey := BitShift(whichMenu, 16) + whichItem;
  461.             END { done }
  462.         ELSE
  463.             wMenuKey := 0;
  464.     END; { wMenuKey }
  465.  
  466. {wHiliteMenu -- unhilite the currently hilited menu title, and hilite a new one }
  467. {    if menuID <> 0 }
  468.     PROCEDURE wHiliteMenu;            { (theMenuBar : wMenuBarHandle; }
  469.                                         { menuID : integer); }
  470.         VAR
  471.             i : integer;
  472.             oldPort : GrafPtr;
  473.     BEGIN
  474.         GetPort(oldPort);
  475.         SetPort(theMenuBar^^.gp);
  476.         IF (theMenuBar^^.hilited <> noneHilited) THEN
  477.             InvertRect(theMenuBar^^.wMenus[theMenuBar^^.hilited].titleRect);
  478.         theMenuBar^^.hilited := noneHilited;
  479.         IF menuID <> 0 THEN
  480.             BEGIN
  481.                 i := 0;
  482.                 WHILE (theMenuBar^^.wMenus[i].mh^^.menuID <> menuID) AND (i < theMenuBar^^.numMenus) DO
  483.                     i := i + 1;
  484.                 IF i <> theMenuBar^^.numMenus THEN
  485.                     BEGIN
  486.                         InvertRect(theMenuBar^^.wMenus[i].titleRect);
  487.                         theMenuBar^^.hilited := i;
  488.                     END; { found menuID }
  489.             END;  { menuID <> 0 }
  490.         SetPort(oldPort);
  491.     END; { wHiliteMenu }
  492.  
  493. END.